﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Xml.Linq;
using System.Linq;
using System.Globalization;
using System.Collections.Generic;
using System.Threading;
using Microsoft.Phone.Net.NetworkInformation;

namespace WeatherFrame
{
    public class WeatherService
    {
        const string KEY = "ReplaceTextWithKey";<--INSERT WORLD WEATHER ONLINE KEY IN STRING BEFORE COMPILING

        public void GetWeatherForecastAsync(Location location)
        {
            if (location.IsWaitingForWeather) return;
            location.IsWaitingForWeather = true;
            // Credit: World Weather Online - 500 request/hour
            string query;
            if ((location.Latitude == 0) && (location.Longitude == 0))
            {
                if (location.IsHere)
                {
                    // location service is only created on demand, hopefully reducing boot time
                    LocationService.Instance.FindCoordinates(location);
                    return;    
                }
                query = Uri.EscapeDataString(location.Name);
            }
            else
            {
                query = location.Latitude + "," + location.Longitude + "&includeLocation=yes";
            }
            string uri = uri = "http://free.worldweatheronline.com/feed/weather.ashx?q=" + query + "&format=xml&num_of_days=5&key="+KEY;

            // initialize a new WebRequest
            var request = (HttpWebRequest)WebRequest.Create(uri);
            var locAndReq = new LocationAndRequest { Location = location, Request = request };

            // start the asynchronous request
            request.BeginGetResponse(new AsyncCallback(ForecastCallback),locAndReq);
        }


        void ForecastCallback(IAsyncResult result)
        {
            //Thread.Sleep(2000);
            WeatherModel wm = App.ViewModel;
            var locAndReq = result.AsyncState as LocationAndRequest;
            var loc = locAndReq.Location;
            loc.IsWaitingForWeather = false;
            var days = new List<WeatherItem>();
            try
            {
                var request = locAndReq.Request;
                var response = request.EndGetResponse(result);

                // get the stream containing the response from the async call
                var streamResult = response.GetResponseStream();

                // load the XML

                var xmlWeather = XElement.Load(streamResult);

                if (false)
                {
                    // current weather conditions
                    var current = xmlWeather.Descendants("current_condition").First();
                    int currentCode = (int)current.Element("weatherCode");

                    var item = wm.Days[0];
                    //item.TimePeriod = "current";
                    item.WeatherCondition = WeatherCondition.FromWeatherCode(currentCode);
                    item.MinTempC = (int)current.Element("temp_C");
                    item.MaxTempC = (int)current.Element("temp_C");
                    item.MinTempF = (int)current.Element("temp_F");
                    item.MaxTempF = (int)current.Element("temp_F");
                }
                if (loc.IsHere)
                {
                    var areaNode = xmlWeather.Descendants("nearest_area").First();
                    loc.Name =(string)areaNode.Element("areaName");
                    loc.Country= (string)areaNode.Element("country");
                    loc.Region = (string)areaNode.Element("region");
                }

                DateTime now = DateTime.Now;
                int ct = 0;
                foreach (var day in xmlWeather.Elements("weather"))
                {
                    string dateString = (string)day.Element("date");
                    DateTime dt = DateTime.ParseExact(dateString, "yyyy-MM-dd", CultureInfo.InvariantCulture);
                    ct++;
                    if ((dt < now.Date) && (ct==1)) continue; // handle yesterday case
                    var it = new WeatherItem { Parent = wm, Location = locAndReq.Location };
                    //if ((days.Count == 0) && (locAndReq.Location.Days != null)) it = locAndReq.Location.Days[0];
                    it.Date = dt;
                    int code = (int)day.Element("weatherCode");
                    // For testing: uncomment to assign a random weather condition
                    //code = WeatherCondition.Conditions[ImageIndex.rnd.Next(WeatherCondition.Conditions.Count - 1) + 1].Code;
                    
                    it.WeatherCondition = WeatherCondition.FromWeatherCode(code);
                    it.MinTempC = (int)day.Element("tempMinC");
                    it.MaxTempC = (int)day.Element("tempMaxC");
                    it.MinTempF = (int)day.Element("tempMinF");
                    it.MaxTempF = (int)day.Element("tempMaxF");
                    it.WindspeedMph = (double)day.Element("windspeedMiles");
                    it.WindDirection = (string)day.Element("winddirection");
                    it.PrecipitationMm = (double)day.Element("precipMM");
                    it.ErrorText = null;
                    it.SetImageFromCondition();
                    days.Add(it);
                }
                if (days.Count == 0)
                {
                    // error state?
                    if (locAndReq.Location.IsNew)
                    {
                        App.ViewModel.BadLocation(locAndReq.Location);
                    }
                }
                else
                {
                    if (locAndReq.Location.IsNew) App.ViewModel.ConfirmLocation(locAndReq.Location);
                    locAndReq.Location.HasWeather = true;
                    locAndReq.Location.Days = days;
                }
            }
            catch (Exception ex)
            {
                string error = "Could not retrieve weather information.";
                if (locAndReq.Location.IsNew)
                {
                    error = "Could not retrieve location information.";
                    if (!IsNetwork) error += Environment.NewLine+"No network connection is available.";
                    App.ViewModel.BadLocation(locAndReq.Location, error);
                }
                else
                {
                    if (!IsNetwork) error += Environment.NewLine + "No network connection is available.";
                    locAndReq.Location.SetError(error);
                }
            }
        }

        public void SearchLocationAsync(string searchText)
        {
            // Credit: World Weather Online - 500 request/hour
            string uri = "http://free.worldweatheronline.com/feed/search.ashx?query=" + Uri.EscapeDataString(searchText) + "&format=xml&num_of_rresults=3&key="+KEY;

            // initialize a new WebRequest
            var request = (HttpWebRequest)WebRequest.Create(uri);

            // start the asynchronous request
            request.BeginGetResponse(new AsyncCallback(SearchCallback), request);
        }

        void SearchCallback(IAsyncResult result)
        {
            //Thread.Sleep(2000);
            var request = result.AsyncState as HttpWebRequest;
            try
            {
                var response = request.EndGetResponse(result);

                // get the stream containing the response from the async call
                var streamResult = response.GetResponseStream();

                var xmlSearch = XElement.Load(streamResult);

                var results = new List<Location>();
                foreach (var resultElement in xmlSearch.Descendants("result"))
                {
                    var loc = new Location();
                    loc.Name = (string)resultElement.Element("areaName");
                    loc.Country = (string)resultElement.Element("country");
                    loc.Region= (string)resultElement.Element("region");
                    loc.Uri = (string)resultElement.Element("weatherUrl");
                    loc.Latitude = (double)resultElement.Element("latitude");
                    loc.Longitude = (double)resultElement.Element("longitude");
                    results.Add(loc);
                }

                App.ViewModel.SearchResults = results;
                App.ViewModel.LocationState = LocationState.SearchResults;
            }
            catch (Exception ex)
            {
                string error = "Could not retrieve location information.";
                if (!IsNetwork) error += Environment.NewLine + "No network connection is available.";
                App.ViewModel.BadLocation(null, error);
            }
        }

        static bool IsNetwork
        {
            get
            {
                return NetworkInterface.NetworkInterfaceType != NetworkInterfaceType.None;
                //return NetworkInterface.GetIsNetworkAvailable();
            }
        }
    }

    class LocationAndRequest {
        internal Location Location {get;set;}
        internal HttpWebRequest Request { get; set; }
    }

    public class SearchResult
    {
    }
}
